#ifndef BUFFER_H
#define BUFFER_H

#include "Common.h"

const int INIT_BUFFER_SIZE = 65536;
const char *CRLF = "\r\n";

class Buffer {

public:
	Buffer():totalSize_(INIT_BUFFER_SIZE), readIndex_(0), writeIndex_(0){
		data_ = (char *) malloc(INIT_BUFFER_SIZE);
	}

	~Buffer() {
		free(data_);
	}

	int getWriteableSize() const {
		return (totalSize_ - writeIndex_);
	}

	int getReadableSize() const {
		// printf("readablesize %d\n", writeIndex_ - readIndex_);
		return (writeIndex_ - readIndex_);
	}

	int getFrontSpareSize() const {
		return readIndex_;
	}

	int doAppend(void *data , int size) {
		if (data != NULL) {
			makeRoom(size);
			memcpy(data_ + writeIndex_, data, size);
			writeIndex_ += size;
		}

		return 0;
	}

	char *getData() const {
		return data_;
	}

	int doAppendChar(char data) {
		makeRoom(1);
		data_[writeIndex_++] = data;
		return 0;
	}

	int doAppendStr(char *data) {
		if (data != NULL) {
			int str_size = strlen(data);
			doAppend(data, str_size);
		}

		return 0;
	}

	char doReadChar(void) {
		char read_ch = data_[readIndex_];
		readIndex_++;
		return read_ch;
	}

	int doSocketRead(int fd) {
		char add_buffer[INIT_BUFFER_SIZE];
		struct iovec vec[2];
		int max_write = getWriteableSize();
		vec[0].iov_base = data_ + writeIndex_;
		vec[0].iov_len = max_write;
		vec[1].iov_base = add_buffer;
		vec[1].iov_len = sizeof(add_buffer);

		int rt = readv(fd, vec, 2);

		if (rt < 0) {
			printf("rt is less than 0\n");
			return -1;
		} else if (rt < max_write) {
			writeIndex_ += rt;
		} else {
			writeIndex_ = totalSize_;
			doAppend(add_buffer, rt - max_write);
		}
		return rt;
	}

private:
	void makeRoom(int size) {
		if (getWriteableSize() >= size)
			return;

		if (getFrontSpareSize() + getWriteableSize() >= size) {
			int read_size = getReadableSize();

			for (int i = 0; i < read_size; ++i) {
				data_[i] = data_[i + readIndex_];
			}
			readIndex_ = 0;
			writeIndex_ = read_size;
		} else {
			void *tmp = realloc(data_, totalSize_ + size);

			if (!tmp) {
				return;
			}

			data_ = (char *) tmp;
			totalSize_ += size;
		}
	}

public:
// private:
	char *data_;
	int writeIndex_;
	int readIndex_;
	int totalSize_;
};

#endif